package com.kova.api.limit;

import com.kova.api.common.Result;
import com.kova.api.common.ResultEnum;
import com.kova.api.exception.CommonException;
import com.kova.api.utils.IpUtil;
import com.kova.api.verify.ParamsVerify;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

//限制接口调用频率处理
@Aspect
@Component
@Slf4j
public class RequestLimitAspect {

    /**
     //写法方式1
    @Synchronized // 作用是创建一个互斥锁，保证只有一个线程对 RequestLimiter.getInstance() 这个变量进行修改。
    @Before(value="@annotation(com.kova.api.limit.RequestLimit)")
    public void aopParameterVerify(JoinPoint point) throws IllegalAccessException, NoSuchMethodException {

        //获取调用类
        Class clazz = point.getTarget().getClass();

        //获取方法名称
        String methodName = point.getSignature().getName();
        MethodSignature signature = (MethodSignature) point.getSignature();

        //获取调用方法对象
        Class[] parameterTypes = signature.getMethod().getParameterTypes();
        Method method = clazz.getMethod(methodName, parameterTypes);

        //获取注解类对象
        Annotation annotation = method.getAnnotation(RequestLimit.class);
        if (annotation == null) {
            //不需要验证
            return;
        }
        RequestLimit nrs = (RequestLimit) annotation;
        if (nrs!=null){
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();//这个RequestContextHolder是Springmvc提供来获得请求的东西
            HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
            String key = IpUtil.getIpAddr(request) + " ：" + request.getServletPath();
            if(!RequestLimiter.getInstance().allowRequest(key,nrs.time())){
                throw new CommonException(ResultEnum.REQUEST_LIMIT);
            }
        }

    }
     **/

    //写法方式2
    @Synchronized // 作用是创建一个互斥锁，保证只有一个线程对 RequestLimiter.getInstance() 这个变量进行修改。
    @Around("execution(* com.kova.api.controller..*.*(..)) && @annotation(nrs)") // 这里要根据自己项目中的controller包路径来配置好
    public Object arround(ProceedingJoinPoint pjp, RequestLimit nrs) throws Throwable {

        if(nrs == null){
            return  pjp.proceed();
        }
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Object[] args = pjp.getArgs();
        String key = IpUtil.getIpAddr(request) + " ：" + request.getServletPath();
        Long time = nrs.time();
        Object o = null;

        //可以改为redis保存处理
       if(RequestLimiter.getInstance().allowRequest(key,time)){
           o = pjp.proceed();
           return o;
       }else{
           log.error("操作过于频繁 {}", key);
           return Result.failed(ResultEnum.REQUEST_LIMIT);
       }

    }

}
